from typing import Dict, List, Literal, TypedDict, TYPE_CHECKING

try:
    from typing import NotRequired
except ImportError:
    from typing_extensions import NotRequired
from ..models import (
    ContainerInfoDict,
    CreateContainerInfoDict,
    HostMachineResourceInfoDict,
)
import requests

import requests

if TYPE_CHECKING:
    from .docker_operator_api import CreateContainerTaskResult, NetworkInfoDict


class NewCreateContainerTaskResp(TypedDict):
    message: str
    task_id: str
    random_ports_mapping: dict[str, int]


class CreateContainerStatusResp(TypedDict):
    error: NotRequired[str]
    status: Literal["waiting", "running", "finished"]
    status_html: List[str]
    result: "CreateContainerTaskResult"


class DockerOperatorClient:
    def __init__(self, host_machine_address="localhost:58080"):
        self.base_url = f"http://{host_machine_address}"
        self.host_machine_address = host_machine_address

    def list_containers(self, all_containers=False) -> list[ContainerInfoDict]:
        params = {"all": all_containers}
        response = requests.get(f"{self.base_url}/containers", params=params)
        response.raise_for_status()
        return response.json()

    def get_container_info(self, container_id_or_name: str) -> ContainerInfoDict:
        """
        Get detailed information about a specific container by its name or ID.

        :param container_id_or_name: The ID or name of the container.
        :return: A dictionary containing the container's information.
        """
        response = requests.get(f"{self.base_url}/containers/{container_id_or_name}")
        response.raise_for_status()
        return response.json()

    def start_container(self, container_name):
        data = {"name": container_name}
        response = requests.post(f"{self.base_url}/containers/start", json=data)
        response.raise_for_status()
        return response.json()

    def stop_container(self, container_name):
        data = {"name": container_name}
        response = requests.post(f"{self.base_url}/containers/stop", json=data)
        response.raise_for_status()
        return response.json()

    def remove_container(self, container_name):
        data = {"name_or_id": container_name}
        response = requests.post(f"{self.base_url}/containers/remove", json=data)
        response.raise_for_status()
        return response.json()

    def new_create_container_task(
        self, info: CreateContainerInfoDict
    ) -> NewCreateContainerTaskResp:
        response = requests.post(
            f"{self.base_url}/containers/create_container_task_start", json=info
        )
        response.raise_for_status()
        return response.json()

    def get_create_container_task_status(
        self, task_id: str
    ) -> CreateContainerStatusResp:
        """
        获取指定 task_id 的 CreateContainerTask 状态和 HTML 日志。

        :param task_id: 任务的唯一标识符。
        :return: 包含任务状态和 HTML 日志的字典。
        """
        response = requests.get(
            f"{self.base_url}/containers/create_container_task_status",
            params={"task_id": task_id},
        )
        response.raise_for_status()
        return response.json()

    def rename_container(self, container_name: str, new_name: str) -> tuple[dict, bool]:
        """
        Rename a container.

        :param container_name: The current name of the container.
        :param new_name: The new name for the container.
        :return: True if the operation was successful, False otherwise.
        """
        data = {"container_name": container_name, "new_name": new_name}
        response = requests.post(f"{self.base_url}/containers/rename", json=data)
        if response.status_code == 200:
            return response.json(), True
        else:
            return response.json(), False

    def export_container_to_image(
        self, container_name: str, image_name: str
    ) -> tuple[str, bool]:
        """
        Export a container to a new image.

        :param container_name: The name of the container to export.
        :param image_name: The name of the new image to create.
        :return: True if the operation was successful, False otherwise.
        """
        data = {"container_name": container_name, "image_name": image_name}
        response = requests.post(
            f"{self.base_url}/containers/export",
            json=data,
        )
        if response.status_code == 200:
            return "", True
        else:
            return response.json()["error"], False

    def list_networks(self) -> "list[NetworkInfoDict]":
        """
        获取所有 Docker 网络的信息。
        """
        response = requests.get(f"{self.base_url}/networks")
        response.raise_for_status()
        return response.json()

    def get_image_layers(self, image_name: str) -> List[str]:
        """
        Get the layer information of a specified image.

        :param image_name: The name of the image.
        :return: A list of layer information.
        """
        params = {"image_name": image_name}
        response = requests.get(f"{self.base_url}/images/layers", params=params)
        response.raise_for_status()
        layers = response.json()
        return layers

    def get_host_machine_resource_info(self) -> HostMachineResourceInfoDict:
        """
        获取当前Linux机器的CPU、内存和磁盘的总量及占用情况。
        """
        response = requests.get(f"{self.base_url}/host_machine/resource_info")
        response.raise_for_status()
        return response.json()
